Borland Online And The Cobb Group Present:


March, 1996 - Vol. 3 No. 3

C++ Language basics - An overview of the new casting operators

by John M. Dlugosz

In addition to the C-style and function-style casts with which you're no doubt already familiar, four new casting operators are more recent additions to the C++ language. They allow you to perform some casts that weren't possible before. More important, they add safety to the language by letting you write code that's easier to maintain. Let's take a look at these additions.

The performers

Table A briefly defines the new casting operators. All four use the same syntax: Put the target type in angle brackets, then put the argument in parentheses. This mimics the syntax for templates. In fact, BC++ 4.x implements the casting operators as pre-declared templates in the parser. But the syntax isn't the difficult part. Rather, you may have difficulty determining which cast to use for which purpose. Let's look at the distinguishing characteristics of each operator.

Table A: New C++ casting operators
Casting operator Purpose
const_cast Can remove const (and volatile)
dynamic_cast Used for runtime-checked downcasts
static_cast Used for "normal" casts
reinterpret_cast Allows "unsafe" and "nonportable" casts

const_cast

You can use a const_cast operator to remove const and/or volatile qualifications from a type. At the same time, the operator can't change the underlying type. For instance, suppose a cast like the following lurked somewhere in a large program:

void f1 (const char* p)
{
char* q= const_cast<char*>(p);    //OK
int* r= const_cast<int*>(p);
	          //compile-time error
}

The C-style cast (char*)p would accomplish the same goal as this cast­­but it's error-prone. The old casts take a "big hammer" approach to the problem­­for instance, this C expression means "turn p into a char* by whatever means is appropriate." If the programmer mistyped the cast or used the wrong variable as the argument, no error would result. Worse yet, someone might modify the program later and change the type of p. If p were changed from const char* to const int*, the old-style cast would go undetected as an error.

The const_cast operator is more specialized, and accepts only jobs that can be done in a certain way. As the preceding code fragment shows, const_cast won't permit a conversion from const char* to int*. You can use it only to change the const and volatile qualifications, and it can't alter the underlying type.

Meanwhile, none of the other casting operators will let you cast away const (or volatile). So the use of const_cast is clear: Use it to cast away const or volatile and never try to use a different operator to cast away const.

dynamic_cast

The dynamic_cast operator is unique in that it performs a runtime check. Assume that C is derived from B, and consider this code:

void f2 (B* b)
{
C* c1= (C*)b;           	           //old-style
C* c2= static_cast<C*>(b);  //means the same 
                            //thing in this 
			   //case
C* c3= dynamic_cast<C*>(b); //runtime
			   //check
}

If an application calls the function with a pointer to an object of type C (or something further derived from C), then the cast works as expected and all three lines are equivalent. On the other hand, if an application calls f2 with a pointer to a B object, the first two lines will produce a bogus pointer as the result of the cast. Only the dynamic_cast operator detects the problem and returns 0.

Note that dynamic_cast operates only on pointers or references to class types. Furthermore, the class has to be polymorphic­­that is, it must contain virtual functions­­because the compiler doesn't generate typeid information for non-polymorphic structures. Use the dynamic_cast operator in cases when you want a runtime check.

static_cast and reinterpret_cast

People typically can't keep these two operators straight. You use the static_cast operator for "normal" casts. It can explicitly perform any standard conversion or do one in reverse. You use the reinterpret_cast operator for "unsafe" and "non-portable" conversions. This explanation is effective only if you know which conversions are "standard."

For example, consider casting a char* to an int*, as follows:

char* s;
int* p1= (int*)s;  //big-hammer approach
int* p2= static_cast<int*>(s);       
   //wrong
int* p3= reinterpret_cast<int*>(s);  
   //correct

To a C programmer who's used to playing fast and loose with pointer types, it may seem counterintuitive that C++ considers this cast a big no-no­­an unsafe and non-portable construct. Nonetheless, static_cast won't permit such a cast: You must use reinterpret_cast instead.

You use the reinterpret_cast operator to convert between a pointer and an integer. You can use it freely to alter the types of pointers and references. That's all it's good for­­for everything else, use static_cast. In fact, if you're not entirely sure which operator to use, use static_cast and see if it produces an error. If it does, change it to reinterpret_cast. Just remember that neither of these can cast away const. Converting a const char* to an int* requires two steps: a const_cast and a reinterpret_cast.

John M. Dlugosz is a C++ consulting expert, developer, and prolific writer. He's a member of Borland's TeamB, he leads the C++ Study Group on CompuServe, and he's the author of C++: A Guru's Handbook. You can reach John via CompuServe at 70007,4657, on the Internet at jdlugosz@dlugosz.com, or on the Web at http://www.dlugosz.com/~jdlugosz/.

Return to the Borland C++ Developer's Journal index

Subscribe to the Borland C++ Developer's Journal


Copyright (c) 1996 The Cobb Group, a division of Ziff-Davis Publishing Company. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of Ziff-Davis Publishing Company is prohibited. The Cobb Group and The Cobb Group logo are trademarks of Ziff-Davis Publishing Company.